home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / noisify.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-02-13  |  21.4 KB  |  823 lines

  1. /*
  2.  * This is a plugin for the GIMP.
  3.  *
  4.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  5.  * Copyright (C) 1996 Torsten Martinsen
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  *
  21.  * $Id: noisify.c,v 1.22.2.1 2003/02/10 00:15:43 tml Exp $
  22.  */
  23.  
  24. /*
  25.  * This filter adds random noise to an image.
  26.  * The amount of noise can be set individually for each RGB channel.
  27.  * This filter does not operate on indexed images.
  28.  *
  29.  * May 2000 tim copperfield [timecop@japan.co.jp]
  30.  * Added dynamic preview.
  31.  *
  32.  * alt@gimp.org. Fixed previews so they handle alpha channels correctly.
  33.  */
  34.  
  35. #include "config.h"
  36.  
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <time.h>
  41.  
  42. #include <gtk/gtk.h>
  43.  
  44. #include <libgimp/gimp.h>
  45. #include <libgimp/gimpui.h>
  46.  
  47. #include "libgimp/stdplugins-intl.h"
  48.  
  49.  
  50. #define SCALE_WIDTH      125
  51. #define TILE_CACHE_SIZE  16
  52. #define PREVIEW_SIZE     128 
  53.  
  54. typedef struct
  55. {
  56.   gint    independent;
  57.   gdouble noise[4];     /*  per channel  */
  58. } NoisifyVals;
  59.  
  60. typedef struct
  61. {
  62.   gint       channels;
  63.   GtkObject *channel_adj[4];
  64.   gint       run;
  65. } NoisifyInterface;
  66.  
  67. /* Declare local functions.
  68.  */
  69. static void       query  (void);
  70. static void       run    (gchar     *name,
  71.               gint       nparams,
  72.               GimpParam    *param,
  73.               gint      *nreturn_vals,
  74.               GimpParam   **return_vals);
  75.  
  76. static void       noisify (GimpDrawable *drawable, gboolean preview_mode);
  77. static gdouble    gauss   (void);
  78.  
  79. static void       fill_preview   (GtkWidget *preview_widget, 
  80.                   GimpDrawable *drawable);
  81. static GtkWidget *preview_widget (GimpDrawable *drawable);
  82.  
  83. static gint       noisify_dialog                   (GimpDrawable *drawable, 
  84.                             gint           channels);
  85. static void       noisify_ok_callback              (GtkWidget     *widget,
  86.                             gpointer       data);
  87. static void       noisify_double_adjustment_update (GtkAdjustment *adjustment,
  88.                             gpointer       data);
  89.  
  90. GimpPlugInInfo PLUG_IN_INFO =
  91. {
  92.   NULL,  /* init_proc */
  93.   NULL,  /* quit_proc */
  94.   query, /* query_proc */
  95.   run,   /* run_proc */
  96. };
  97.  
  98. static NoisifyVals nvals =
  99. {
  100.   TRUE,
  101.   { 0.20, 0.20, 0.20, 0.20 }
  102. };
  103.  
  104. static NoisifyInterface noise_int =
  105. {
  106.   0,
  107.   { NULL, NULL, NULL, NULL },
  108.   FALSE     /* run */
  109. };
  110.  
  111. static GtkWidget *preview;
  112. static guchar    *preview_cache;
  113. static gint       preview_cache_rowstride;
  114. static gint       preview_cache_bpp;
  115.  
  116.  
  117. MAIN ()
  118.  
  119. static void
  120. query (void)
  121. {
  122.   static GimpParamDef args[] =
  123.   {
  124.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  125.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  126.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  127.     { GIMP_PDB_INT32, "independent", "Noise in channels independent" },
  128.     { GIMP_PDB_FLOAT, "noise_1", "Noise in the first channel (red, gray)" },
  129.     { GIMP_PDB_FLOAT, "noise_2", "Noise in the second channel (green, gray_alpha)" },
  130.     { GIMP_PDB_FLOAT, "noise_3", "Noise in the third channel (blue)" },
  131.     { GIMP_PDB_FLOAT, "noise_4", "Noise in the fourth channel (alpha)" }
  132.   };
  133.   static gint nargs = sizeof (args) / sizeof (args[0]);
  134.  
  135.   gimp_install_procedure ("plug_in_noisify",
  136.               "Adds random noise to a drawable's channels",
  137.               "More here later",
  138.               "Torsten Martinsen",
  139.               "Torsten Martinsen",
  140.               "May 2000",
  141.               N_("<Image>/Filters/Noise/Noisify..."),
  142.               "RGB*, GRAY*",
  143.               GIMP_PLUGIN,
  144.               nargs, 0,
  145.               args, NULL);
  146. }
  147.  
  148. static void
  149. run (gchar   *name,
  150.      gint     nparams,
  151.      GimpParam  *param,
  152.      gint    *nreturn_vals,
  153.      GimpParam **return_vals)
  154. {
  155.   static GimpParam values[1];
  156.   GimpDrawable *drawable;
  157.   GimpRunModeType run_mode;
  158.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  159.  
  160.   run_mode = param[0].data.d_int32;
  161.  
  162.   *nreturn_vals = 1;
  163.   *return_vals = values;
  164.  
  165.   values[0].type = GIMP_PDB_STATUS;
  166.   values[0].data.d_status = status;
  167.  
  168.   /*  Get the specified drawable  */
  169.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  170.  
  171.   switch (run_mode)
  172.     {
  173.     case GIMP_RUN_INTERACTIVE:
  174.       INIT_I18N_UI();
  175.       /*  Possibly retrieve data  */
  176.       gimp_get_data ("plug_in_noisify", &nvals);
  177.  
  178.       /*  First acquire information with a dialog  */
  179.       if (! noisify_dialog (drawable, drawable->bpp))
  180.     {
  181.       gimp_drawable_detach (drawable);
  182.       return;
  183.     }
  184.       break;
  185.  
  186.     case GIMP_RUN_NONINTERACTIVE:
  187.       INIT_I18N();
  188.       /*  Make sure all the arguments are there!  */
  189.       if (nparams != 8)
  190.     {
  191.       status = GIMP_PDB_CALLING_ERROR;
  192.     }
  193.       else
  194.     {
  195.       nvals.independent = param[3].data.d_int32 ? TRUE : FALSE;
  196.       nvals.noise[0]    = param[4].data.d_float;
  197.       nvals.noise[1]    = param[5].data.d_float;
  198.       nvals.noise[2]    = param[6].data.d_float;
  199.       nvals.noise[3]    = param[7].data.d_float;
  200.     }
  201.       break;
  202.  
  203.     case GIMP_RUN_WITH_LAST_VALS:
  204.       INIT_I18N();
  205.       /*  Possibly retrieve data  */
  206.       gimp_get_data ("plug_in_noisify", &nvals);
  207.       break;
  208.  
  209.     default:
  210.       break;
  211.     }
  212.  
  213.   /*  Make sure that the drawable is gray or RGB color  */
  214.   if (gimp_drawable_is_rgb (drawable->id) ||
  215.       gimp_drawable_is_gray (drawable->id))
  216.     {
  217.       gimp_progress_init (_("Adding Noise..."));
  218.       gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
  219.  
  220.       /*  seed the random number generator  */
  221. #ifdef G_OS_WIN32
  222.       SRAND_FUNC (time (NULL));
  223. #else
  224.       srand (time (NULL));
  225. #endif
  226.  
  227.       /*  compute the luminosity which exceeds the luminosity threshold  */
  228.       noisify (drawable, FALSE);
  229.  
  230.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  231.     gimp_displays_flush ();
  232.  
  233.       /*  Store data  */
  234.       if (run_mode == GIMP_RUN_INTERACTIVE) {
  235.     gimp_set_data ("plug_in_noisify", &nvals, sizeof (NoisifyVals));
  236.     g_free(preview_cache);
  237.       }
  238.     }
  239.   else
  240.     {
  241.       /* gimp_message ("blur: cannot operate on indexed color images"); ??? BLUR ??? */
  242.       status = GIMP_PDB_EXECUTION_ERROR;
  243.     }
  244.  
  245.   values[0].data.d_status = status;
  246.  
  247.   gimp_drawable_detach (drawable);
  248. }
  249.  
  250. static void
  251. preview_do_row(gint    row,
  252.            gint    width,
  253.            guchar *even,
  254.            guchar *odd,
  255.            guchar *src)
  256. {
  257.   gint    x;
  258.   
  259.   guchar *p0 = even;
  260.   guchar *p1 = odd;
  261.   
  262.   gdouble    r, g, b, a;
  263.   gdouble    c0, c1;
  264.   
  265.   for (x = 0; x < width; x++) 
  266.     {
  267.       if (preview_cache_bpp == 4)
  268.     {
  269.       r = ((gdouble)src[x*4+0]) / 255.0;
  270.       g = ((gdouble)src[x*4+1]) / 255.0;
  271.       b = ((gdouble)src[x*4+2]) / 255.0;
  272.       a = ((gdouble)src[x*4+3]) / 255.0;
  273.     }
  274.       else if (preview_cache_bpp == 3)
  275.     {
  276.       r = ((gdouble)src[x*3+0]) / 255.0;
  277.       g = ((gdouble)src[x*3+1]) / 255.0;
  278.       b = ((gdouble)src[x*3+2]) / 255.0;
  279.       a = 1.0;
  280.     }
  281.       else
  282.     {
  283.       r = ((gdouble)src[x*preview_cache_bpp+0]) / 255.0;
  284.       g = b = r;
  285.       if (preview_cache_bpp == 2)
  286.             a = ((gdouble)src[x*preview_cache_bpp+1]) / 255.0;
  287.       else
  288.         a = 1.0;
  289.     }
  290.       
  291.       if ((x / GIMP_CHECK_SIZE) & 1) 
  292.     {
  293.       c0 = GIMP_CHECK_LIGHT;
  294.       c1 = GIMP_CHECK_DARK;
  295.     } 
  296.       else 
  297.     {
  298.       c0 = GIMP_CHECK_DARK;
  299.       c1 = GIMP_CHECK_LIGHT;
  300.     }
  301.       
  302.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  303.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  304.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  305.       
  306.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  307.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  308.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  309.       
  310.     } /* for */
  311.   
  312.   if ((row / GIMP_CHECK_SIZE) & 1)
  313.     {
  314.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)odd,  0, row, width); 
  315.     }
  316.   else
  317.     {
  318.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)even, 0, row, width); 
  319.     }
  320. }
  321.  
  322. static void
  323. noisify (GimpDrawable *drawable, 
  324.      gboolean   preview_mode)
  325. {
  326.   GimpPixelRgn src_rgn, dest_rgn;
  327.   guchar *src_row, *dest_row;
  328.   guchar *src, *dest, *dest_data;
  329.   gint row, col, b;
  330.   gint x1, y1, x2, y2, p, bpp = 3;
  331.   gint noise;
  332.   gint progress = 0, max_progress = 0;
  333.   gpointer pr;
  334.   gint row_stride = 0;
  335.   guchar *odd = NULL;
  336.   guchar *even = NULL;
  337.   /* initialize */
  338.  
  339.   noise = 0;
  340.  
  341.   if (preview_mode) 
  342.     {
  343.       x1 = y1 = 0;
  344.       x2 = GTK_PREVIEW (preview)->buffer_width;
  345.       y2 = GTK_PREVIEW (preview)->buffer_height;
  346.       bpp = preview_cache_bpp;
  347.       row_stride = preview_cache_rowstride;
  348.       even = g_malloc (x2 * 3);
  349.       odd  = g_malloc (x2 * 3);
  350.     } 
  351.   else 
  352.     {
  353.       gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  354.       gimp_pixel_rgn_init (&src_rgn, drawable,
  355.                x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
  356.       gimp_pixel_rgn_init (&dest_rgn, drawable,
  357.                x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
  358.       /* Initialize progress */
  359.       progress = 0;
  360.       max_progress = (x2 - x1) * (y2 - y1);
  361.     }
  362.  
  363.   if (preview_mode) 
  364.     {
  365.       dest_data = g_malloc (row_stride * y2);
  366.  
  367.       for (row = 0; row < y2; row++)
  368.     {
  369.       src  = preview_cache + row * row_stride;
  370.       dest = dest_data + row * row_stride;
  371.       
  372.       for (col = 0; col < x2; col++)
  373.         {
  374.           if (nvals.independent == FALSE)
  375.         noise = (gint) (nvals.noise[0] * gauss() * 127);
  376.  
  377.           for (b = 0; b < bpp; b++)
  378.         {
  379.           if (nvals.independent == TRUE)
  380.             noise = (gint) (nvals.noise[b] * gauss() * 127);
  381.  
  382.           if (nvals.noise[b] > 0.0)
  383.             {
  384.               p = src[b] + noise;
  385.               if (p < 0)
  386.                 p = 0;
  387.               else if (p > 255)
  388.                 p = 255;
  389.               dest[b] = p;
  390.             }
  391.           else
  392.             dest[b] = src[b];
  393.  
  394.         }
  395.           src += bpp;
  396.           dest += bpp;
  397.         }
  398.     }
  399.  
  400.       for (row = 0; row < y2; row++)
  401.     {
  402.       preview_do_row(row,x2,even,odd,dest_data + row * row_stride);
  403.     }
  404.  
  405.       gtk_widget_queue_draw (preview);
  406.  
  407.       if(even)
  408.     g_free(even);
  409.       
  410.       if(odd)
  411.     g_free(odd);
  412.  
  413.     } 
  414.   else 
  415.     {
  416.       for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
  417.        pr != NULL;
  418.        pr = gimp_pixel_rgns_process (pr))
  419.     {
  420.       src_row = src_rgn.data;
  421.       dest_row = dest_rgn.data;
  422.  
  423.       for (row = 0; row < src_rgn.h; row++)
  424.         {
  425.           src = src_row;
  426.           dest = dest_row;
  427.           
  428.           for (col = 0; col < src_rgn.w; col++)
  429.         {
  430.           if (nvals.independent == FALSE)
  431.             noise = (gint) (nvals.noise[0] * gauss() * 127);
  432.           
  433.           for (b = 0; b < src_rgn.bpp; b++)
  434.             {
  435.               if (nvals.independent == TRUE)
  436.             noise = (gint) (nvals.noise[b] * gauss() * 127);
  437.               
  438.               if (nvals.noise[b] > 0.0)
  439.             {
  440.               p = src[b] + noise;
  441.               if (p < 0)
  442.                 p = 0;
  443.               else if (p > 255)
  444.                 p = 255;
  445.               dest[b] = p;
  446.             }
  447.               else
  448.             dest[b] = src[b];
  449.               
  450.             }
  451.           src += src_rgn.bpp;
  452.           dest += dest_rgn.bpp;
  453.         }
  454.           
  455.           src_row += src_rgn.rowstride;
  456.           dest_row += dest_rgn.rowstride;
  457.         }
  458.       
  459.       /* Update progress */
  460.       progress += src_rgn.w * src_rgn.h;
  461.       gimp_progress_update ((double) progress / (double) max_progress);
  462.     }
  463.  
  464.       /*  update the blurred region  */
  465.       gimp_drawable_flush (drawable);
  466.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  467.       gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  468.  
  469.     } /* endif normal mode */
  470. }
  471.  
  472. static gint
  473. noisify_dialog (GimpDrawable *drawable, 
  474.         gint       channels)
  475. {
  476.   GtkWidget *dlg;
  477.   GtkWidget *main_vbox;
  478.   GtkWidget *abox;
  479.   GtkWidget *toggle;
  480.   GtkWidget *frame;
  481.   GtkWidget *table;
  482.   GtkObject *adj;
  483.   gchar *buffer;
  484.   gint   i;
  485.  
  486.   gimp_ui_init ("noisify", FALSE);
  487.  
  488.   dlg = gimp_dialog_new (_("Noisify"), "noisify",
  489.              gimp_standard_help_func, "filters/noisify.html",
  490.              GTK_WIN_POS_MOUSE,
  491.              FALSE, TRUE, FALSE,
  492.  
  493.              _("OK"), noisify_ok_callback,
  494.              NULL, NULL, NULL, TRUE, FALSE,
  495.              _("Cancel"), gtk_widget_destroy,
  496.              NULL, 1, NULL, FALSE, TRUE,
  497.  
  498.              NULL);
  499.  
  500.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  501.               GTK_SIGNAL_FUNC (gtk_main_quit),
  502.               NULL);
  503.  
  504.   main_vbox = gtk_vbox_new (FALSE, 2);
  505.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 0);
  506.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox, TRUE, TRUE, 0);
  507.   gtk_widget_show (main_vbox);
  508.  
  509.   /* preview */
  510.   frame = gtk_frame_new (_("Preview"));
  511.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  512.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  513.   gtk_widget_show (frame);
  514.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  515.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  516.   gtk_container_add (GTK_CONTAINER (frame), abox);
  517.   gtk_widget_show (abox);
  518.   frame = gtk_frame_new (NULL);
  519.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  520.   gtk_container_add (GTK_CONTAINER (abox), frame);
  521.   gtk_widget_show (frame);
  522.   preview = preview_widget (drawable);
  523.   gtk_container_add (GTK_CONTAINER (frame), preview);
  524.   noisify (drawable, TRUE); /* preview noisify */
  525.   gtk_widget_show (preview);
  526.   
  527.   /*  parameter settings  */
  528.   frame = gtk_frame_new (_("Parameter Settings"));
  529.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  530.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  531.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
  532.  
  533.   table = gtk_table_new (channels + 1, 3, FALSE);
  534.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  535.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  536.   gtk_table_set_row_spacing (GTK_TABLE (table), 0, 4);
  537.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  538.   gtk_container_add (GTK_CONTAINER (frame), table);
  539.  
  540.   toggle = gtk_check_button_new_with_label (_("Independent"));
  541.   gtk_table_attach (GTK_TABLE (table), toggle, 0, 3, 0, 1, GTK_FILL, 0, 0, 0);
  542.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  543.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  544.               &nvals.independent);
  545.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), nvals.independent);
  546.   gtk_widget_show (toggle);
  547.  
  548.   noise_int.channels = channels;
  549.  
  550.   if (channels == 1) 
  551.     {
  552.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  553.                   _("Gray:"), SCALE_WIDTH, 0,
  554.                   nvals.noise[0], 0.0, 1.0, 0.01, 0.1, 2,
  555.                   TRUE, 0, 0,
  556.                   NULL, NULL);
  557.  
  558.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  559.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  560.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  561.               &nvals.noise[0]);
  562.       noise_int.channel_adj[0] = adj;
  563.     }
  564.   else if (channels == 2)
  565.     {
  566.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  567.                   _("Gray:"), SCALE_WIDTH, 0,
  568.                   nvals.noise[0], 0.0, 1.0, 0.01, 0.1, 2,
  569.                   TRUE, 0, 0,
  570.                   NULL, NULL);
  571.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  572.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  573.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  574.               &nvals.noise[0]);
  575.       noise_int.channel_adj[0] = adj;
  576.  
  577.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  578.                   _("Alpha:"), SCALE_WIDTH, 0,
  579.                   nvals.noise[1], 0.0, 1.0, 0.01, 0.1, 2,
  580.                   TRUE, 0, 0,
  581.                   NULL, NULL);
  582.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  583.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  584.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  585.               &nvals.noise[1]);
  586.       noise_int.channel_adj[1] = adj;
  587.     }
  588.   
  589.   else if (channels == 3)
  590.     {
  591.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  592.                   _("Red:"), SCALE_WIDTH, 0,
  593.                   nvals.noise[0], 0.0, 1.0, 0.01, 0.1, 2,
  594.                   TRUE, 0, 0,
  595.                   NULL, NULL);
  596.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  597.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  598.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  599.               &nvals.noise[0]);
  600.       noise_int.channel_adj[0] = adj;
  601.  
  602.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  603.                   _("Green:"), SCALE_WIDTH, 0,
  604.                   nvals.noise[1], 0.0, 1.0, 0.01, 0.1, 2,
  605.                   TRUE, 0, 0,
  606.                   NULL, NULL);
  607.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  608.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  609.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  610.               &nvals.noise[1]);
  611.       noise_int.channel_adj[1] = adj;
  612.  
  613.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 3,
  614.                   _("Blue:"), SCALE_WIDTH, 0,
  615.                   nvals.noise[2], 0.0, 1.0, 0.01, 0.1, 2,
  616.                   TRUE, 0, 0,
  617.                   NULL, NULL);
  618.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  619.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  620.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  621.               &nvals.noise[2]);
  622.       noise_int.channel_adj[2] = adj;
  623.     }
  624.  
  625.   else if (channels == 4)
  626.     {
  627.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  628.                   _("Red:"), SCALE_WIDTH, 0,
  629.                   nvals.noise[0], 0.0, 1.0, 0.01, 0.1, 2,
  630.                   TRUE, 0, 0,
  631.                   NULL, NULL);
  632.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  633.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  634.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  635.               &nvals.noise[0]);
  636.       noise_int.channel_adj[0] = adj;
  637.  
  638.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  639.                   _("Green:"), SCALE_WIDTH, 0,
  640.                   nvals.noise[1], 0.0, 1.0, 0.01, 0.1, 2,
  641.                   TRUE, 0, 0,
  642.                   NULL, NULL);
  643.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  644.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  645.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  646.               &nvals.noise[1]);
  647.       noise_int.channel_adj[1] = adj;
  648.  
  649.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 3,
  650.                   _("Blue:"), SCALE_WIDTH, 0,
  651.                   nvals.noise[2], 0.0, 1.0, 0.01, 0.1, 2,
  652.                   TRUE, 0, 0,
  653.                   NULL, NULL);
  654.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  655.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  656.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  657.               &nvals.noise[2]);
  658.       noise_int.channel_adj[2] = adj;
  659.  
  660.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 4,
  661.                   _("Alpha:"), SCALE_WIDTH, 0,
  662.                   nvals.noise[3], 0.0, 1.0, 0.01, 0.1, 2,
  663.                   TRUE, 0, 0,
  664.                   NULL, NULL);
  665.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  666.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  667.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  668.               &nvals.noise[3]);
  669.       noise_int.channel_adj[3] = adj;
  670.     }
  671.   else
  672.     {
  673.       for (i = 0; i < channels; i++)
  674.     {
  675.       buffer = g_strdup_printf (_("Channel #%d:"), i);
  676.  
  677.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, i + 1,
  678.                       buffer, SCALE_WIDTH, 0,
  679.                       nvals.noise[i], 0.0, 1.0, 0.01, 0.1, 2,
  680.                       TRUE, 0, 0,
  681.                       NULL, NULL);
  682.           gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  683.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  684.                   GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  685.                   &nvals.noise[i]);
  686.       noise_int.channel_adj[i] = adj;
  687.  
  688.       g_free (buffer);
  689.     }
  690.     }
  691.  
  692.   gtk_widget_show (frame);
  693.   gtk_widget_show (table);
  694.  
  695.   gtk_widget_show (dlg);
  696.  
  697.   gtk_main ();
  698.   gdk_flush ();
  699.  
  700.   return noise_int.run;
  701. }
  702.  
  703. /*
  704.  * Return a Gaussian (aka normal) random variable.
  705.  *
  706.  * Adapted from ppmforge.c, which is part of PBMPLUS.
  707.  * The algorithm comes from:
  708.  * 'The Science Of Fractal Images'. Peitgen, H.-O., and Saupe, D. eds.
  709.  * Springer Verlag, New York, 1988.
  710.  */
  711. static gdouble
  712. gauss (void)
  713. {
  714.   gint i;
  715.   gdouble sum = 0.0;
  716.  
  717.   for (i = 0; i < 4; i++)
  718. #ifdef G_OS_WIN32
  719.     sum += RAND_FUNC () & 0x7FFF;
  720. #else
  721.     sum += rand () & 0x7FFF;
  722. #endif
  723.  
  724.   return sum * 5.28596089837e-5 - 3.46410161514;
  725. }
  726.  
  727. static void
  728. noisify_ok_callback (GtkWidget *widget,
  729.              gpointer   data)
  730. {
  731.   noise_int.run = TRUE;
  732.  
  733.   gtk_widget_destroy (GTK_WIDGET (data));
  734. }
  735.  
  736. static void
  737. noisify_double_adjustment_update (GtkAdjustment *adjustment,
  738.                   gpointer       data)
  739. {
  740.   GimpDrawable *drawable;
  741.   
  742.   gimp_double_adjustment_update (adjustment, data);
  743.   drawable = gtk_object_get_data (GTK_OBJECT (adjustment), "drawable");
  744.   noisify (drawable, TRUE);
  745.  
  746.   if (! nvals.independent)
  747.     {
  748.       gint i;
  749.  
  750.       for (i = 0; i < noise_int.channels; i++)
  751.     if (adjustment != GTK_ADJUSTMENT (noise_int.channel_adj[i]))
  752.       gtk_adjustment_set_value (GTK_ADJUSTMENT (noise_int.channel_adj[i]),
  753.                     adjustment->value);
  754.     }
  755. }
  756.  
  757. static GtkWidget *
  758. preview_widget (GimpDrawable *drawable)
  759. {
  760.   gint       size;
  761.  
  762.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  763.   fill_preview (preview, drawable);
  764.   size = GTK_PREVIEW (preview)->rowstride * GTK_PREVIEW (preview)->buffer_height;
  765.   return preview;
  766. }
  767.  
  768. static void
  769. fill_preview (GtkWidget *widget, 
  770.           GimpDrawable *drawable)
  771. {
  772.   GimpPixelRgn  srcPR;
  773.   gint       width;
  774.   gint       height;
  775.   gint       x1, x2, y1, y2;
  776.   gint       bpp;
  777.   gint       y;
  778.   guchar    *src;
  779.   guchar    *even, *odd;
  780.   
  781.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  782.  
  783.   if (x2 - x1 > PREVIEW_SIZE)
  784.     x2 = x1 + PREVIEW_SIZE;
  785.   
  786.   if (y2 - y1 > PREVIEW_SIZE)
  787.     y2 = y1 + PREVIEW_SIZE;
  788.   
  789.   width  = x2 - x1;
  790.   height = y2 - y1;
  791.   bpp    = gimp_drawable_bpp (drawable->id);
  792.   
  793.   if (width < 1 || height < 1)
  794.     return;
  795.  
  796.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  797.  
  798.   gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, x2, y2, FALSE, FALSE);
  799.  
  800.   even = g_malloc (width * 3);
  801.   odd  = g_malloc (width * 3);
  802.   src  = g_malloc (width * bpp);
  803.   preview_cache = g_malloc(width * bpp * height);
  804.   preview_cache_rowstride = width * bpp;
  805.   preview_cache_bpp = bpp;
  806.  
  807.  
  808.   for (y = 0; y < height; y++)
  809.     {
  810.       gimp_pixel_rgn_get_row (&srcPR, src, x1, y + y1, width);
  811.       memcpy(preview_cache + (y*width*bpp),src,width*bpp);
  812.     }
  813.  
  814.   for (y = 0; y < height; y++)
  815.     {
  816.       preview_do_row(y,width,even,odd,preview_cache + (y*width*bpp));
  817.     }
  818.  
  819.   g_free (even);
  820.   g_free (odd);
  821.   g_free (src);
  822. }
  823.